﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;


namespace HITs
{
    public class CoreFunctions
    {
        #region ------- Biến
        public static List<string> _listNgayGiaoDich = new List<string>();
        
        public static string _pathToFile = "";

        public static string _pathHOSE_HNX= "";
        public static string _infoData = "";

        public static Random _ran = new Random();

        public static string _ngayBatDau = "";
        public static string _ngayKetThuc = "";
        public static int _soNgayGiaoDich = 0;


        #region * Các hệ số tính giá tổng hợp
        public static float HeSoGiaMoCua = 0;
        public static float HeSoGiaDongCua = 1;
        public static float HeSoGiaCaoNhat = 0;
        public static float HeSoGiaThapNhat = 0;
        #endregion

        #region * Biến cho Chart
        public static List<List<float>> _chart_listValues = new List<List<float>>();
        public static List<string> _chart_listName = new List<string>();
        public static string _chart_nameStock = "";

        public static List<float> _chart_listGia = new List<float>();
        public static List<string> _chart_listNgayGiaoDich = new List<string>();
        #endregion

        #endregion

        #region ------- Hàm xử lý - Xuly_
        /// <summary>
        /// Lấy chuỗi ngày giờ theo ngày hiện tại
        /// </summary>
        /// <returns></returns>
        public static string Xuly_LayNgayHienTaiChoBatdau()
        {
            ///Lấy ngày hệ thống theo dạng YYYYMMDD            
            int day = DateTime.Now.Day;
            int month = DateTime.Now.Month;
            int year = DateTime.Now.Year;

            string text = year.ToString();
            if (month >= 10)
                text += month.ToString();
            else
                text += "0" + month.ToString();

            if (day >= 10)
                text += day.ToString();
            else
                text += "0" + day.ToString();

            return text;         
        }

        /// <summary>
        /// Lấy list ngày giao dịch trong file Data Stock
        /// </summary>
        /// <param name="path"></param>
        public static void Xuly_LayListNgayGiaoDich(string path)
        {
            List<List<string>> listData = CoreFunctions.File_LoadAnyFile(path, false, new string[] { ",","\t" });

            _listNgayGiaoDich = new List<string>();

            foreach (List<string> EachRow in listData)
                if (EachRow.Count > 0 && _listNgayGiaoDich.Contains(EachRow[1]) == false)
                    _listNgayGiaoDich.Add(EachRow[1]);
            /// Note: list ngày giao dịch sẽ theo sắp xếp theo DES dựa trên đầu vào của dữ liệu datastock
        }

        /// <summary>
        /// Đếm ký tự 
        /// </summary>
        /// <param name="StrCount">text cần đếm số ký tự</param>
        /// <param name="Limit">số lượng ký tự giới hạn</param>
        /// <param name="LowLimit">số ký tự cần trả về trong trường hợp dưới Limit</param>
        /// <param name="HighLimit">số ký tự cần trả về trong trường hợp trên Limit</param>
        /// <param name="StrReturn">Ký tự chuỗi trả về</param>
        public static string Xuly_ChuoiTraVe(string StrCount, int Limit, int LowLimit, int HighLimit, string StrReturn)
        {
            string result = "";
            if (StrCount.Length <= Limit)
                for (int i = 0; i < LowLimit; i++)
                    result += StrReturn;
            else
                for (int i = 0; i < HighLimit; i++)
                    result += StrReturn;
            return result;
        }

        /// <summary>
        /// Lấy list ngày giao dịch trong file Data Stock
        /// Xuất list để tận dụng việc đã đọc file DataStock
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static List<List<string>> Xuly_LayListNgayGiaoDich_OutFile(string path)
        {
            List<List<string>> listData = CoreFunctions.File_LoadAnyFile(path, false, new string[] { ",","\t" });

            _listNgayGiaoDich = new List<string>();

            foreach (List<string> EachRow in listData)
                if (EachRow.Count > 0 && _listNgayGiaoDich.Contains(EachRow[1]) == false)
                    _listNgayGiaoDich.Add(EachRow[1]);
            return listData;
        }

        /// <summary>
        /// Lấy các ngày giao trong một tháng - một năm bất kỳ
        /// </summary>
        /// <param name="Nam"></param>
        /// <param name="Thang"></param>
        /// <returns></returns>
        public static List<string> Xuly_LayNgayGiaoDichTrongThang(string Nam, string Thang)
        {
            string text = Nam + Thang;
            List<string> result = new List<string>();
            foreach (string str in _listNgayGiaoDich)
                if (str.Substring(0, 6) == text)
                    result.Add(str);
            return result;
        }

        /// <summary>
        /// Lấy ngày giao dịch gần nhất so với ngày được xét
        /// Chuyển string --> int: ưu tiên những ngày gần trong tháng đó
        /// </summary>
        /// <param name="Ngay"></param>
        /// <returns></returns>
        public static string Xuly_LayNgayGiaoDichGanNhat(string Ngay)
        {
            string result = "";
            if (_listNgayGiaoDich.Count != 0)
            {
                int ngaygiaodich = int.Parse(Ngay);
                int idmin = 0, rangeMin, rangeTemp;
                int ngayxet = int.Parse(_listNgayGiaoDich[0]);

                rangeMin = ngaygiaodich - ngayxet;
                if (rangeMin < 0)
                    rangeMin = -rangeMin;

                for (int i = 1; i < _listNgayGiaoDich.Count; i++)
                {
                    ngayxet = int.Parse(_listNgayGiaoDich[i]);
                    rangeTemp = ngaygiaodich - ngayxet;

                    if (rangeTemp < 0)
                        rangeTemp = -rangeTemp;
                    else
                        if (rangeTemp == 0)
                        {
                            idmin = i;
                            break;
                        }

                    if (rangeMin > rangeTemp)
                    {
                        idmin = i;
                        rangeMin = rangeTemp;
                    }
                }
                result = _listNgayGiaoDich[idmin];
            }
            return result;
        }

        /// <summary>
        /// Chuyển đổi một list chứa các phần tử int sang list chứa các phần tử float
        /// </summary>
        /// <param name="listValues"></param>
        /// <returns></returns>
        public static List<float> Xuly_ConvertListIntToListFloat(List<int> listValues)
        {
            List<float> result = new List<float>();
            foreach (int value in listValues)
                result.Add(value);
            return result;
        }

        /// <summary>
        /// Chuyển chuỗi YYYYMMDD thành YYYY.MM.DD
        /// </summary>
        /// <param name="ngay"></param>
        /// <returns></returns>
        public static string Xuly_ChuyenChuoiDataStock(string ngay)
        {
            string year = ngay.Substring(0, 4);
            string month = ngay.Substring(4, 2);
            string day = ngay.Substring(6, 2);

            string text = year + "." + month +"." + day;
            return text;
        }

        /// <summary>
        /// Loại bỏ các phần tử trên ma trận có độ đồng dạng thấp hơn minSimilar
        /// </summary>
        /// <param name="matrix">ma trận vuông đồng dạng [levelMatrix,levelMatrix] đối xứng qua đường chéo chính</param>
        /// <param name="levelMatrix">cấp ma trận</param>
        /// <param name="minSimilar">độ đồng dạng tối thiểu</param>
        public static float[,] Xuly_LoaiBoPhanTuItDongDang(float[,] matrix, int levelMatrix, float minSimilar)
        {
            for (int i = 0; i < levelMatrix - 1; i++)
                for (int j = i + 1; j < levelMatrix; j++)
                    if (matrix[i, j] < minSimilar)
                    {
                        matrix[i, j] = 0f;
                        matrix[j, i] = 0f;
                    }
            return matrix;
        }

        /// <summary>
        /// Loại bỏ các phần tử trên ma trận có độ đồng dạng thấp hơn minSimilar
        /// </summary>
        /// <param name="matrix">ma trận vuông đồng dạng [levelMatrix,levelMatrix] đối xứng qua đường chéo chính</param>
        /// <param name="levelMatrix">cấp ma trận</param>
        /// <param name="minSimilar">độ đồng dạng tối thiểu</param>
        /// <param name="maTranNhiPhan">true: chuyển về ma trận nhị phân. False thì ngược lại</param>
        /// <returns></returns>
        public static float[,] Xuly_LoaiBoPhanTuItDongDang(float[,] matrix, int levelMatrix, float minSimilar, bool maTranNhiPhan)
        {
            for (int i = 0; i < levelMatrix - 1; i++)
                for (int j = i + 1; j < levelMatrix; j++)
                    if (matrix[i, j] < minSimilar)
                    {
                        matrix[i, j] = 0.0f;
                        matrix[j, i] = 0.0f;
                    }
                    else
                        if (maTranNhiPhan == true)
                        {
                            matrix[i, j] = 1.0f;
                            matrix[j, i] = 1.0f;
                        }

            return matrix;
        }

        /// <summary>
        /// Chuyển ma trận số thực sang ma trận dạng nhị phân [0,1].
        /// Những phần tử khác 0 chuyển thàng 1.
        /// </summary>
        /// <param name="matrix"></param>
        /// <param name="levelMatrix"></param>
        /// <returns></returns>
        public static float[,] Xuly_ChuyenSangMaTranNhiPhan(float[,] matrix, int levelMatrix)
        {
            for (int i = 0; i < levelMatrix; i++)
                for (int j = 0; j < levelMatrix; j++)
                    if (matrix[i, j] != 0.00f)
                        matrix[i,j] = 1.0f;
            return matrix;
        }

        /// <summary>
        /// Tính ngày tương lai (bắt đầu, kết thúc) với một khoảng ngày cho trước. 
        /// Nếu không có sẽ lấy ngày gần nhất.
        /// </summary>
        /// <param name="ngayBatDauHienTai"></param>
        /// <param name="soNgayTruoc"></param>
        /// <param name="ngayBatDauTuongLai"></param>
        /// <param name="ngayKetThucTuongLai"></param>
        public static void Xuly_TinhNgayTuongLai(string ngayBatDauHienTai,int soNgayTruoc, out string ngayBatDauTuongLai, out string ngayKetThucTuongLai)
        {
            ngayBatDauTuongLai = "";
            ngayKetThucTuongLai = "";
            int idHienTai = CoreFunctions._listNgayGiaoDich.IndexOf(ngayBatDauHienTai);
            if (idHienTai <= 1)
                return;
            else
            {
                ngayKetThucTuongLai = CoreFunctions._listNgayGiaoDich[idHienTai - 1];
                idHienTai = idHienTai - soNgayTruoc;
                if (idHienTai <= 0)
                    idHienTai = 0;

                ngayBatDauTuongLai = CoreFunctions._listNgayGiaoDich[idHienTai];
            }
        }
        
        /// <summary>
        /// Sort theo dạng QuickSort - DES
        /// </summary>
        /// <param name="listValues"></param>
        /// <param name="left"></param>
        /// <param name="right"></param>
        public static void Xuly_QuickSortDES(List<float> listValues, int left, int right)
        {
            int i = left, j = right;
            float mid = listValues[(i + j) / 2], temp;

            do
            {
                while (listValues[i] > mid) i++;
                while (listValues[j] < mid) j--;
                if (i <= j)
                {
                    temp = listValues[i];
                    listValues[i] = listValues[j];
                    listValues[j] = temp;
                    i++; j--;
                }
            } while (i <= j);

            if (left < j) CoreFunctions.Xuly_QuickSortDES(listValues, left, j);
            if (i < right) CoreFunctions.Xuly_QuickSortDES(listValues, i, right);
        }

        /// <summary>
        /// Tính hạng của mỗi giá trị phần tử trong danh sách
        /// Hạng phần tử tính từ 1
        /// </summary>
        /// <param name="listValues">danh sách giá trị</param>
        /// <param name="IsASC">True: ASC. False: DES</param>
        /// <returns>danh sách hạng (tính từ 1) tương ứng mỗi phần tử</returns>
        public static List<int> Xuly_TinhHangDanhSach(List<float> listValues, bool IsASC)
        {
            List<float> listTemp = new List<float>();
            List<int> listRanking = new List<int>();
            int index;

            foreach (float values in listValues)
                listTemp.Add(values);

            if (IsASC == true)
                listTemp.Sort();
            else
                CoreFunctions.Xuly_QuickSortDES(listTemp, 0, listTemp.Count - 1);

            foreach (float value in listValues)
            {
                index = listTemp.IndexOf(value);
                index++;
                listRanking.Add(index);
            }

            return listRanking;
        }

        /// <summary>
        /// Đảo ngược list 
        /// </summary>
        /// <param name="listValues"></param>
        /// <returns></returns>
        public static List<float> Xuly_DaoNguocList(List<float> listValues)
        {
            List<float> result = new List<float>();
            foreach (float values in listValues)            
                result.Insert(0, values);            
            return result;
        }

        public static List<int> Xuly_DaoNguocList(List<int> listValues)
        {
            List<int> result = new List<int>();
            foreach (int values in listValues)
                result.Insert(0, values);
            return result;
        }

        public static List<float> Xuly_LayNphantudautien(List<float> listValues, int soPhantu)
        {
            List<float> listResult = new List<float>();

            for (int i = 0; i < listValues.Count; i++)
            {
                if (i < soPhantu)
                    listResult.Add(listValues[i]);
                else
                    break;
            }
            return listResult;
        }

        public static List<string> Xuly_LayNphantudautien(List<string> listValues, int soPhantu)
        {
            List<string> listResult = new List<string>();

            for (int i = 0; i < listValues.Count; i++)
                if (i <= soPhantu)
                    listResult.Add(listValues[i]);
                else
                    break;

            return listResult;
        }

        public static string Xuly_LayThongTin_HistogramMACD(List<float> listHistogram)
        {
            string result = "";
            int sodinh, soNgayCachDinh = 2;
            
            List<float> listSong1 = new List<float>();

            /// Xác định số đỉnh của sóng hiện thời
            for (int i = 0; i < listHistogram.Count - 1; i++)
            {
                listSong1.Add(listHistogram[i]);
                if ((listHistogram[i] > 0 && listHistogram[i + 1] < 0)
                    || (listHistogram[i] < 0 && listHistogram[i + 1] > 0))
                    break;
            }
            if (listSong1.Count > 5)
            {
                float tileDanhMuc = 0f;
                float chechlechSuonA2Ngay = -1f, chechlechSuonB2Ngay = -1f;
                float chechlech = (float)Math.Log(listSong1[0] / listSong1[2]);

                chechlech = (float)Math.Abs(chechlech);
                chechlech = (float)Math.Round(chechlech * 100, 1);
                

                List<int> listViTriDinh = new List<int>();
                List<float> listChechLech = new List<float>();
                listChechLech.Add(0.10f);
                
                sodinh = CoreFunctions.Tk_SoDinh1Song_HistogramMACD(listSong1, soNgayCachDinh, listChechLech, false, ref listViTriDinh);
                if(listViTriDinh.Count > 0 && listViTriDinh[0] >= 2)
                {
                    chechlechSuonB2Ngay = (float)Math.Abs(Math.Log(listSong1[listViTriDinh[0]] / listSong1[listViTriDinh[0] + 2]));
                    chechlechSuonA2Ngay = (float)Math.Abs(Math.Log(listSong1[listViTriDinh[0]] / listSong1[listViTriDinh[0] - 2]));

                    chechlechSuonA2Ngay = (float)Math.Round(chechlechSuonA2Ngay * 100, 0);
                    chechlechSuonB2Ngay = (float)Math.Round(chechlechSuonB2Ngay * 100, 0);
                }

                result += "\nSố ngày: " + soNgayCachDinh + " - chêch lệch: 10%"  + " - Số đỉnh: " + sodinh + "\n"; 
                if (listHistogram[0] >= 0)
                    tileDanhMuc = ShareData.Testing_BackTest_HistorgramMACD_Statistic_Chechlech(sodinh, chechlech, true);
                else
                    tileDanhMuc = ShareData.Testing_BackTest_HistorgramMACD_Statistic_Chechlech(sodinh, chechlech, false);

                result += "Ch.lệch ngày 0,2  : " + chechlech + "%\n";
                result += "==> Tỉ lệ Danh Mục: " + tileDanhMuc + "%\n";

                result += "Ch.lệch từ sườn A (2): " + chechlechSuonA2Ngay + "%\n";
                result += "Ch.lệch từ sườn B (2): " + chechlechSuonB2Ngay + "%\n";
                
                if (listSong1[0] > 0)
                {
                    result += "\nSố ngày: 3 - Chêch lệch: 45% - Số đỉnh: "
                        + CoreFunctions.Tk_SoDinh1Song_HistogramMACD(listSong1, 3, 0.45f);
                    result += "\nSố ngày: 3 - Chêch lệch: 34% - Số đỉnh: "
                        + CoreFunctions.Tk_SoDinh1Song_HistogramMACD(listSong1, 3, 0.34f);
                }
                else
                {
                    result += "\nSố ngày 3 - Chêch lệch 43% - Số đỉnh: "
                        + CoreFunctions.Tk_SoDinh1Song_HistogramMACD(listSong1, 3, 0.43f);
                    result += "\nSố ngày 3 - Chêch lệch 35% - Số đỉnh: "
                        + CoreFunctions.Tk_SoDinh1Song_HistogramMACD(listSong1, 3, 0.35f);
                }

                result += "\n\n";
                result += "Số ngày sóng 1: " + listSong1.Count;
            }
            else
                result = "Sóng chưa đủ ngày xem xét (>=5)";
            return result;
        }
        #endregion

        #region ------- File - File_
        /// <summary>
        /// Load bất kỳ file nào
        /// Nếu bỏ qua dòng đầu tiên: IsReadHeader = false. Ngược lại, true
        /// </summary>
        /// <param name="path">đường dẫn file</param>
        /// <param name="IsReadHeader">Đọc dòng đầu tiên hay không</param>
        /// <param name="Splitter">các ký tự để tách thành các phần trong dòng</param>
        /// <returns></returns>
        public static List<List<string>> File_LoadAnyFile(string path, bool IsReadHeader, string[] Splitter)
        {
            List<List<string>> result = new List<List<string>>();
            string text;

            FileStream fs = new FileStream(path, FileMode.Open);
            StreamReader reader = new StreamReader(fs, Encoding.ASCII);

            if (IsReadHeader == false)
                reader.ReadLine();

            while (reader.EndOfStream != true)
            {
                text = reader.ReadLine();
                if (text != "")
                {
                    string[] part = text.Split(Splitter, StringSplitOptions.RemoveEmptyEntries);
                    result.Add(new List<string>());
                    result[result.Count - 1].AddRange(part);
                }
            }
            reader.Close();
            fs.Close();

            return result;
        }

        public static List<string> File_LoadAnyFile(string path)
        {
            List<string> listResult = new List<string>();

            FileStream fs = new FileStream(path, FileMode.Open);
            StreamReader reader = new StreamReader(fs, Encoding.UTF8);
            string str = "";
            while (reader.EndOfStream != true)
            {
                str = reader.ReadLine();
                if (str != "")
                {
                    listResult.Add(str);
                }
            }
            reader.Close();
            fs.Close();
            return listResult;
        }

        /// <summary>
        /// Load bất kỳ file nào
        /// Nếu  bỏ qua số dòng ở phần đầu của file
        /// </summary>
        /// <param name="path">đường dẫn file</param>
        /// <param name="numberRowSkip">số dòng bị bỏ qua (không đọc)</param>
        /// <param name="Splitter">các ký tự để tách thành các phần trong dòng</param>
        /// <returns></returns>
        public static List<List<string>> File_LoadAnyFile(string path, int numberRowSkip, string[] Splitter)
        {
            List<List<string>> result = new List<List<string>>();
            string text;

            FileStream fs = new FileStream(path, FileMode.Open);
            StreamReader reader = new StreamReader(fs, Encoding.ASCII);
            int count = 0;

            while (reader.EndOfStream != true)
            {
                if (count < numberRowSkip)
                {
                    reader.ReadLine();
                    count++;
                }
                else
                {
                    text = reader.ReadLine();
                    if (text != "")
                    {
                        string[] part = text.Split(Splitter, StringSplitOptions.RemoveEmptyEntries);
                        result.Add(new List<string>());
                        result[result.Count - 1].AddRange(part);
                    }
                }
            }
            reader.Close();
            fs.Close();

            return result;
        }

        /// <summary>
        /// Ghi file bất kỳ
        /// </summary>
        /// <param name="path">đường dẫn thư mục File kết thúc là dấu \</param>
        /// <param name="NameFile">thông thường là nameFile.txt</param>
        /// <param name="Content">danh sách các dòng của file</param>
        public static void File_WriteAnyFile(string path, string NameFile, List<string> Content)
        {
            FileStream fs = new FileStream(path + NameFile, FileMode.Create);
            StreamWriter writer = new StreamWriter(fs, Encoding.ASCII);

            foreach (string str in Content)            
                writer.WriteLine(str);
            
            writer.Flush();
            writer.Close();
            fs.Close();
        }
        public static void File_WriteAnyFile(string path, List<string> Content)
        {
            FileStream fs = new FileStream(path, FileMode.Create);
            StreamWriter writer = new StreamWriter(fs, Encoding.ASCII);

            foreach (string str in Content)
                writer.WriteLine(str);

            writer.Flush();
            writer.Close();
            fs.Close();
        }
        public static void File_AppendAnyFile(string path, string NameFile, List<string> Content)
        {
            FileStream fs = new FileStream(path + NameFile, FileMode.Append);
            StreamWriter writer = new StreamWriter(fs, Encoding.ASCII);

            foreach (string str in Content)
                writer.WriteLine(str);

            writer.Flush();
            writer.Close();
            fs.Close();
        }

        /// <summary>
        /// Tách file All data Stock thành sàn HOSE
        /// Dựa trên file thống kê các mã HOSE (Ck_HOSE.txt) trong thư mục Data
        /// </summary>
        public static void File_SplitAllDataStockToHOSE(string pathToAllDataStock)
        {
            List<List<string>> listNameStockHOSE = CoreFunctions.File_LoadAnyFile(System.Windows.Forms.Application.StartupPath + @"\Data\CK_HOSE.txt", 0, new string[] { "\t" });
            List<List<string>> listAllStock = CoreFunctions.File_LoadAnyFile(pathToAllDataStock, false, new string[] { "," });
            List<List<string>> listStockHOSE = new List<List<string>>();

            listAllStock.Sort(CoreFunctions.Compare_ListListString); /// sắp xếp lại theo mã CP tăng dần và ngày cập nhật giảm dần

            foreach (List<string> listValues in listAllStock)                  
                foreach(List<string> listName in listNameStockHOSE)
                    if (listName[0] == listValues[0])
                    {
                        listStockHOSE.Add(listValues);
                        break;
                    }            

            List<string> listContent = new List<string>();           
            string text, title = "<Ticker>,<DTYYYYMMDD>,<Open>,<High>,<Low>,<Close>,<Volume>";
            foreach (List<string> listValues in listStockHOSE)
            {
                text = "";
                foreach (string str in listValues)
                    text += str + ",";
                text = text.Substring(0, text.Length - 1);
                listContent.Add(text);
            }                    

            listContent.Insert(0, title);
            CoreFunctions.File_WriteAnyFile(System.Windows.Forms.Application.StartupPath + @"\Data\", "MetaStock_HOSE_TungNgay.txt", listContent);
        }

        public static void File_ProcessDataStockHOSE()
        {
            List<string> listFileHOSE = CoreFunctions.File_LoadAnyFile(@"C:\Users\hpsc\Desktop\filemetastock\^vnindex.txt");
            List<string> listMetaHOSE = CoreFunctions.File_LoadAnyFile(@"C:\Users\hpsc\Documents\Code\Phan tich - Du doan chung khoan\HITs\bin\Debug\Data\MetaStock_HOSE.txt");
            List<string> listDateNew = new List<string>();
            string name_CP = "";
            int count_remove = 0;

            #region Lấy ngày giao dịch hiện tại của VNINDEX
            for (int i = 1; i < 3; i++)
            {
                string[] part = listFileHOSE[i].Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                listDateNew.Add(part[1]);
            }
            #endregion

            #region Xóa những CP có ngày hiện tại không khớp với VNINDEX
            for (int i = 1; i < listMetaHOSE.Count; i++)
            {
                string[] part = listMetaHOSE[i].Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                if (name_CP != part[0])
                {
                    name_CP = part[0];
                    if (part[1] != listDateNew[0])
                    {
                        count_remove = 0;
                        for (int j = i; j < listMetaHOSE.Count; j++)
                        {
                            string[] part_temp = listMetaHOSE[j].Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                            if (name_CP == part_temp[0])
                            {
                                listMetaHOSE.RemoveAt(j);
                                j--;
                                count_remove++;
                            }
                            else
                                break;
                        }
                        if (count_remove > 0)
                            i--;
                    }
                }
            }
            #endregion

            #region Điều chỉnh các giá trị các ngày khác 0
            //for (int i = 1; i < listMetaHOSE.Count; i++)
            //{
            //    string[] part = listMetaHOSE[i].Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
            //    if(part
            //}
            #endregion

            #region Ghi File
            List<string> listContent = new List<string>();
            listContent.Add(listMetaHOSE[0]);
            for (int i = 1; i < listMetaHOSE.Count; i++)
                listContent.Add(listMetaHOSE[i]);
            CoreFunctions.File_WriteAnyFile(@"C:\Users\hpsc\Documents\Code\Phan tich - Du doan chung khoan\HITs\bin\Debug\Data\", "MetaStock_HOSE_processed.txt", listContent);

            #endregion

        }

        public static List<string> File_LoadBig4()
        {
            List<List<string>> listresult = File_LoadAnyFile(System.Windows.Forms.Application.StartupPath + @"\Data\Big4.txt", false, new string[] { });
            List<string> result = new List<string>();
            foreach(List<string> list in listresult)
                result.Add(list[0]);
            return result;            
        }
        #endregion

        #region ------- Kiểm tra - KiemTra_
        /// <summary>
        /// Kiểm tra ngày có nằm giữa ngày bắt đầu và kết thúc. 
        /// ngày bắt đầu phải lớn ngày kết thúc. 
        /// Được tính dưới dạng YYYYMMDD
        /// </summary>
        /// <param name="ngayKiemTra"></param>
        /// <param name="ngayBatDau"></param>
        /// <param name="ngayKetThuc"></param>
        /// <returns>Nằm giữa: True. Ngược lại False</returns>
        public static bool KiemTra_NgayNamGiuaBatDauVaKetThuc(string ngayKiemTra,string ngayBatDau, string ngayKetThuc)
        {
            int NgayKiemTra = int.Parse(ngayKiemTra);
            int NgayBatDau = int.Parse(ngayBatDau);
            int NgayKetThuc = int.Parse(ngayKetThuc);

            if (NgayBatDau >= NgayKiemTra && NgayKiemTra >= NgayKetThuc)            
                return true;
            
            return false;
        }
        #endregion

        #region ------- Thống kê mô tả - Tk_
        /// <summary>
        /// Tính trung bình của một list các phần tử float
        /// </summary>
        /// <param name="listValues"></param>
        /// <returns></returns>
        public static float Tk_GetAverage(List<float> listValues)
        {
            float result = 0f;
            if (listValues.Count != 0)
                for (int i = 0; i < listValues.Count; i++)                
                    if (listValues[i].ToString() != "NaN")
                        result += (listValues[i] - result) / (i + 1);
            return result;
        }

        public static float Tk_GetAverage(List<int> listValues)
        {
            float result = 0f;
            if (listValues.Count != 0)
                for (int i = 0; i < listValues.Count; i++)
                    if (listValues[i].ToString() != "NaN")
                        result += (listValues[i] - result) / (i + 1);
            return result;
        }

        public static float Tk_GetMax(List<float> listValues)
        {          
            float val_max = listValues[0];
            for (int i = 1; i < listValues.Count; i++)
            {
                if (listValues[i] > val_max)
                    val_max = listValues[i];
            }
            return val_max;
        }

        public static float Tk_GetMin(List<float> listValues)
        {
            float val_min = listValues[0];
            for (int i = 1; i < listValues.Count; i++)
            {
                if (listValues[i] < val_min)
                    val_min = listValues[i];
            }
            return val_min;
        }

        public static int Tk_SoDinh1Song_HistogramMACD(List<float> listValues, int soNgayCachDinh)
        {
            int sodinh = CoreFunctions.Tk_SoDinh1Song_HistogramMACD(listValues, soNgayCachDinh, 0.01f);
            return sodinh;
        }

        public static int Tk_SoDinh1Song_HistogramMACD(List<float> listValues, int soNgayCachDinh, float percentChechlech)
        {
            int sodinh = 0;
            List<float> listChechlech = new List<float>();
            listChechlech.Add(percentChechlech);
            List<int> listVitriDinh = new List<int>();
            sodinh = Tk_SoDinh1Song_HistogramMACD(listValues, soNgayCachDinh, listChechlech, false, ref listVitriDinh);
            return sodinh;
        }

        public static int Tk_SoDinh1Song_HistogramMACD(List<float> listValues, int soNgayCachDinh, List<float> percentChechlech)            
        {
            int sodinh = 0;
            List<int> listViTriDinh = new List<int>();
            sodinh = Tk_SoDinh1Song_HistogramMACD(listValues, soNgayCachDinh, percentChechlech, false, ref listViTriDinh);

            return sodinh;
        }

        public static int Tk_SoDinh1Song_HistogramMACD(List<float> listValues, int soNgayCachDinh, List<float> percentChechlech
            , bool flagSuonA, ref List<int> listViTriDinh)
        {
            /// flagSuonA: true sóng đi từ sườn A sang sườn B (sau --> đỉnh --> trước khi hình thành đỉnh)
            /// Ngược lại, sóng đi từ sườn B sang sườn A.
            /// 
            /// listvalues có giá trị sát thực tế nhất là vị trí thứ 0
            int sodinh = 0;
            int xuhuong = 0; /// 1 là tăng - 2 là giảm
            int count_list = percentChechlech.Count;
            float temp;
            bool flag;
            listViTriDinh = new List<int>();

            if (listValues[0] > 0)
                flag = true;
            else
                flag = false;

            if (flagSuonA)
            {
                #region Đi theo hướng từ sườn A sang B (sau khi có đỉnh ==> hình thành đỉnh ==> trước khi hình thành đỉnh sóng)
                for (int i = 0; i < listValues.Count - soNgayCachDinh; i++)
                {
                    if ((xuhuong == 0 || xuhuong == 1) && listValues[i] <= listValues[i + 1])
                        xuhuong = 1;
                    else if ((xuhuong == 0 || xuhuong == 2) && listValues[i] >= listValues[i + 1])
                        xuhuong = 2;
                    else
                    {
                        if ((xuhuong == 1 && flag) || (!flag && xuhuong == 2))
                            for (int j = 1; j <= soNgayCachDinh; j++)
                            {
                                temp = (float)Math.Abs(Math.Log(listValues[i] / listValues[i + j]));
                                if ((sodinh < count_list && temp >= percentChechlech[sodinh])
                                    || (sodinh >= count_list && temp >= percentChechlech[count_list - 1]))
                                {
                                    sodinh++;
                                    listViTriDinh.Add(i);
                                    break;
                                }
                            }

                        if (xuhuong == 1)
                            xuhuong = 2;
                        else if (xuhuong == 2)
                            xuhuong = 1;
                    }
                }
                #endregion
            }
            else
            {
                #region Đi theo hướng từ sườn B sang A (trước khi có đỉnh ==> hình thành đỉnh ==> sau khi hình thành đỉnh sóng)
                for (int i = listValues.Count - 1; i > soNgayCachDinh; i--)
                {
                    if ((xuhuong == 0 || xuhuong == 1) && listValues[i] >= listValues[i - 1])
                        xuhuong = 1;
                    else if ((xuhuong == 0 || xuhuong == 2) && listValues[i] <= listValues[i - 1])
                        xuhuong = 2;
                    else
                    {
                        if ((xuhuong == 1 && flag) || (!flag && xuhuong == 2))
                            for (int j = 1; j <= soNgayCachDinh; j++)
                            {
                                temp = (float)Math.Abs(Math.Log(listValues[i] / listValues[i - j]));
                                if ((sodinh < count_list && temp >= percentChechlech[sodinh])
                                    || (sodinh >= count_list && temp >= percentChechlech[count_list - 1]))
                                {
                                    sodinh++;
                                    listViTriDinh.Add(i);
                                    break;
                                }
                            }

                        if (xuhuong == 1)
                            xuhuong = 2;
                        else if (xuhuong == 2)
                            xuhuong = 1;
                    }
                }
                #endregion
            }

            return sodinh;
        }

        public static List<int> Tk_TinHieuMACD(List<float> listValues, int soNgayCachDinh)
        {
            /// listvalues có giá trị sát thực tế nhất là vị trí thứ 0          
            int xuhuong = 0; /// 1 là tăng - 2 là giảm
            List<int> listResult = new List<int>();

            for (int i = 0; i < listValues.Count - soNgayCachDinh; i++)
            {
                if ((xuhuong == 0 || xuhuong == 1) && listValues[i] >= listValues[i + soNgayCachDinh])
                    xuhuong = 1;
                else if ((xuhuong == 0 || xuhuong == 2) && listValues[i] <= listValues[i + soNgayCachDinh])
                    xuhuong = 2;
                else
                {
                    if (i - soNgayCachDinh >= 0)
                        listResult.Add(i - soNgayCachDinh);
                    if (xuhuong == 1) xuhuong = 2;
                    if (xuhuong == 2) xuhuong = 1;
                }
            }

            return listResult;
        }

        public static float Tk_GetSum(List<float> listValues)
        {
            float result = 0f;
            foreach (float value in listValues)
                result += value;
            return result;
        }
        /// <summary>
        /// Tính độ lệch chuẩn của một list các phần tử float - vai trò là quần thể
        /// </summary>
        /// <param name="listValues"></param>
        /// <returns></returns>
        public static float Tk_PopularStandardDeviation(List<float> listValues)
        {
            /// Tính trung bình
            float AverageValue = Tk_GetAverage(listValues);

            float sd = 0f;
            foreach (float value in listValues)
                sd += ((value - AverageValue) * (value - AverageValue));
            sd = (float)Math.Round(Math.Sqrt(sd / listValues.Count), 3);
            AverageValue = (float)Math.Round(AverageValue, 3);
            return sd;
        }

        public static float Tk_PopularStandardDeviation(List<int> listValues)
        {
            /// Tính trung bình
            float AverageValue = Tk_GetAverage(listValues);

            float sd = 0f;
            foreach (int value in listValues)
                if (value.ToString() != "NaN")
                    sd += (value - AverageValue) * (value - AverageValue);
            sd = (float)Math.Round(Math.Sqrt(sd / listValues.Count), 3);
            AverageValue = (float)Math.Round(AverageValue, 3);
            return sd;
        }
        public static List<float> Tk_PopularStandardDeviation(List<float> listValues, int soNgay)
        {
            List<float> result = new List<float>();
            List<float> temp = new List<float>();
            if (listValues.Count > soNgay)
                for (int i = 0; i < listValues.Count - soNgay; i++)
                {
                    temp = new List<float>();
                    for (int j = 0; j < soNgay; j++)
                        temp.Add(listValues[i + j]);
                    result.Add(Tk_PopularStandardDeviation(temp));
                }
            return result;
        }
                
        /// <summary>
        /// Tính độ lệch chuẩn một list các phần tử float - vai trò là mẫu trong một quần thể nào đó
        /// </summary>
        /// <param name="listValues"></param>
        /// <returns></returns>
        public static float Tk_SampleStandardDeviation(List<float> listValues)
        {
            float SampleAverageValue = Tk_GetAverage(listValues);           

            float sd = 0f;
            foreach (float value in listValues)
                sd += (value - SampleAverageValue) * (value - SampleAverageValue);
            sd = (float)Math.Round(Math.Sqrt(sd / (listValues.Count - 1)), 2);

            return sd;
        }

        /// <summary>
        /// Tính CoEfficent từ độ lệch chuẩn và giá trị trung bình
        /// CoEfficent được dùng để so sánh 2 đại lượng bất kỳ không quan tâm đến đơn vị đo
        /// </summary>
        /// <param name="StandardDeviation"></param>
        /// <param name="AverageValue"></param>
        /// <returns></returns>
        public static float Tk_GetCoEfficentOfVariation(float StandardDeviation, float AverageValue)
        {
            float result = StandardDeviation / AverageValue;
            result = (float)Math.Round(result, 3);
            return result;
        }

        /// <summary>
        /// Tính Z-Scores (standard score) nhằm chuẩn hóa các phần tử trong một list các phần tử float
        /// Z-Score được dùng kết hợp 2 list của 2 đại lượng bất kỳ, không quan tâm đến đơn vị đo
        /// Z-score chi tiết hơn CoEfficent vì áp dụng cho từng phần tử trong list. Còn CoEfficent áp dụng cho list
        /// </summary>
        /// <param name="listValues"></param>
        /// <returns></returns>
        public static List<float> Tk_GetZScores(List<float> listValues)
        {
            List<float> result = new List<float>();
            if (listValues.Count != 0)
            {
                float average = Tk_GetAverage(listValues);
                float standardDeviation = 0f;
                foreach (float value in listValues)
                    standardDeviation += (value - average) * (value - average);
                standardDeviation = (float)Math.Round(Math.Sqrt(standardDeviation / listValues.Count), 3);

                float temp;
                foreach (float values in listValues)
                {
                    temp = (values - average) / standardDeviation;
                    temp = (float)Math.Round(temp, 3);
                    result.Add(temp);
                }
            }
            return result;
        }

        public static List<float> Tk_GetZScores(List<int> listValues)
        {
            List<float> listConvert = Xuly_ConvertListIntToListFloat(listValues);
            List<float> result = new List<float>();
            if (listValues.Count != 0)
            {
                float average = Tk_GetAverage(listConvert);
                float standardDeviation = 0f;
                foreach (int value in listConvert)
                    standardDeviation += (value - average) * (value - average);
                standardDeviation = (float)Math.Sqrt(standardDeviation / listValues.Count);

                float temp;
                foreach (float values in listConvert)
                {
                    temp = (values - average) / standardDeviation;
                    temp = (float)Math.Round(temp, 3);
                    result.Add(temp);
                }
            }
            return result;
        }
        
        /// <summary>
        /// Tính SharpeRation. Tỉ lệ hay được dùng trong các Hedge Fund
        /// </summary>
        /// <param name="listValues">Số giá trị phải lớn 250</param>
        /// <returns></returns>
        public static float Tk_GetSharpeRatio(List<float> listValues)
        {
            float Result;
            List<float> daily_rest = new List<float>();
            daily_rest.Add(0);
            for (int i = listValues.Count - 2; i >= 0; i--)
                daily_rest.Insert(0, listValues[i] / listValues[i + 1] - 1);
            float avg_dailyrest = Tk_GetAverage(daily_rest);
            float std_dailyrest = Tk_PopularStandardDeviation(daily_rest);
            Result = (float)Math.Sqrt(12f) * avg_dailyrest / std_dailyrest;
            Result = (float)Math.Round(Result, 3);
            return Result;
        }

        public static float Tk_GetSharpeRatio_Volatility(List<float> listValues)
        {
            float Result;
            List<float> daily_rest = new List<float>();
            daily_rest.Add(0);
            for (int i = listValues.Count - 2; i >= 0; i--)
                daily_rest.Insert(0, listValues[i] / listValues[i + 1] - 1);

            float avg_dailyrest = Tk_GetAverage(daily_rest);
            float volatility_dailyrest = MR_TinhVolatility_ContinuousMethod(daily_rest, daily_rest.Count);

            Result = (float)Math.Sqrt(12f) * avg_dailyrest / volatility_dailyrest;
            Result = (float)Math.Round(Result, 3);
            return Result;
        }

        public static List<float> Tk_GetSharpeRatio(List<float> listValues, int soNgay)
        {
            List<float> result = new List<float>();
            List<float> temp = new List<float>();
            if (listValues.Count > soNgay)
                for (int i = 0; i < listValues.Count - soNgay; i++)
                {
                    temp = new List<float>();
                    for (int j = 0; j < soNgay; j++)
                        temp.Add(listValues[i + j]);
                    result.Add(Tk_GetSharpeRatio(temp));
                }
            return result;
        }

        public static List<float> Tk_GetSharpeRatio_Volatility(List<float> listValues, int soNgay)
        {
            List<float> result = new List<float>();
            List<float> temp = new List<float>();
            if (listValues.Count > soNgay)
                for (int i = 0; i < listValues.Count - soNgay; i++)
                {
                    temp = new List<float>();
                    for (int j = 0; j < soNgay; j++)
                        temp.Add(listValues[i + j]);
                    result.Add(Tk_GetSharpeRatio_Volatility(temp));
                }
            return result;
        }

        public static List<float> Tk_GetDailyReturn(List<float> listValues)
        {
            /// Lưu ý hàm sử dụng: danh sách có quá khứ bắt đầu từ 0 - hiện tại nằm ở vị trí cuối danh sách
            List<float> listResult = new List<float>();
            listResult.Add(0.0f);
            for (int i = 0; i < listValues.Count - 1; i++)
                listResult.Add(listValues[i + 1] / listValues[i] - 1);
            return listResult;
        }

        /// <summary>
        /// Lấy hạng của mỗi phần tử trong danh sách
        /// Biến bool quy định: true|Ascending ; false|Desceding
        /// </summary>
        /// <param name="listValues"></param>
        /// <returns></returns>
        public static List<int> Tk_GetRanking(List<float> listValues, bool IsAsc)
        {
            List<int> result = new List<int>();
            List<float> temp = new List<float>();
            foreach (float f in listValues)
                temp.Add(f);
            temp.Sort();
            int t = listValues.Count;
            if (IsAsc)
            {
                for (int i = 0; i < t; i++)
                {
                    result.Add(temp.IndexOf(listValues[i]) + 1);
                }
            }
            else
            {
                for (int i = 0; i < t; i++)
                {
                    result.Add(t - temp.LastIndexOf(listValues[i]));
                }
            }

            return result;
        }

        /// <summary>
        /// Xử lý danh sách rồi xuất thông tin max, min, average
        /// </summary>
        /// <param name="listValues"></param>
        /// <param name="max"></param>
        /// <param name="min"></param>
        /// <param name="average"></param>
        public static void Tk_ThongKeMoTa(List<float> listValues, out float max, out float min, out float average)
        {
            if (listValues.Count != 0)
            {
                max = listValues[0];
                min = listValues[0];
                average = listValues[0];
                for (int i = 1; i < listValues.Count; i++)
                {
                    if (max < listValues[i])
                        max = listValues[i];

                    if (min > listValues[i])
                        min = listValues[i];

                    average += listValues[i];
                }
                average = (float)Math.Round(average / listValues.Count, 3);
            }
            else
            {
                max = 0;
                min = 0;
                average = 0;
            }
        }

        public static void Tk_ThongKeMoTa(List<int> listValues, out float max, out float min, out float average)
        {
            if (listValues.Count != 0)
            {
                max = listValues[0];
                min = listValues[0];
                average = listValues[0];
                for (int i = 1; i < listValues.Count; i++)
                {
                    if (max < listValues[i])
                        max = listValues[i];

                    if (min > listValues[i])
                        min = listValues[i];

                    average += listValues[i];
                }
                average = (float)Math.Round(average / listValues.Count, 3);
            }
            else
            {
                max = 0;
                min = 0;
                average = 0;
            }
        }

        /// <summary>
        /// Tính trung bình - trung bình dương - trung bình âm của một danh sách
        /// </summary>
        /// <param name="listValues"></param>
        /// <param name="avgTotal"></param>
        /// <param name="avgPositive"></param>
        /// <param name="avgNegative"></param>
        /// <param name="SaiSo">số làm tròn sau dấu phẩy thập phân</param>
        public static void TK_ThongKeAverage(List<float> listValues, out float avgTotal, out float avgPositive, out float avgNegative
            ,out int CountPositive, out int CountNegative, int SaiSo)
        {
            List<float> listPositive = new List<float>();
            List<float> listNegative = new List<float>();

            foreach (float value in listValues)
                if (value >= 0.0000f)
                    listPositive.Add(value);
                else
                    listNegative.Add(value);

            avgTotal = (float)Math.Round(CoreFunctions.Tk_GetAverage(listValues), SaiSo);
            avgPositive = (float)Math.Round(CoreFunctions.Tk_GetAverage(listPositive), SaiSo);
            avgNegative = (float)Math.Round(CoreFunctions.Tk_GetAverage(listNegative), SaiSo);
            CountPositive = listPositive.Count;
            CountNegative = listNegative.Count;
        }

        /// <summary>
        /// Thống kê tiền lời từ danh sách ngày mua bán
        /// </summary>
        /// <param name="listVal"> list giá - ngày hiện tại là ở vị trí 0 của danh sách</param>
        /// <param name="listNgayMuaBan">ngày mua (giá trị dương) - ngày bán (giá trị âm)</param>
        /// <returns> trả về giá trị % - số thực (0.)</returns>
        public static float Tk_Thongke_PhanTramLoi(List<float> listVal, List<int> listNgayMuaBan)
        {
            float   result = 0f,
                    giatriTienMat = 1f;                                
            int val_int;           
            bool flag_GiuCP = false; /// false là trạng thái không giữ cổ phiếu. Ngược lại, là true.

            for (int i = listNgayMuaBan.Count - 1; i > 0; i--)
            {
                if (flag_GiuCP == false && listNgayMuaBan[i] >= 0)                
                    flag_GiuCP = true;
                else if (flag_GiuCP == true && listNgayMuaBan[i] < 0)
                {
                    val_int = listNgayMuaBan[i] * -1;
                
                    for (int j = val_int + 1; j < listNgayMuaBan.Count; j++)                    
                        if (listNgayMuaBan[j] >= 0)
                        {
                            giatriTienMat = giatriTienMat * ( 1 + (listVal[i] - listVal[j]) / listVal[j]);
                            break;
                        }
                    flag_GiuCP = false;
                }
            }
            result = (giatriTienMat - 1);

            return result;
        }
        #endregion

        #region ------- Tính toán mở rộng - MR_
        /// <summary>
        /// Tính danh sách sự khác biệt giữa 2 phần tử liên tiếp trong list.
        /// Tính Trái - Phải
        /// Danh sách kết quả sẽ ít hơn danh sách đầu vào 1 phần tử
        /// </summary>
        /// <param name="listValues">list này nên có thứ tự</param>
        /// <returns></returns>
        public static List<float> MR_TinhDanhSachThayDoiGiua2PhanTuLienTiep(List<float> listValues)
        {
            List<float> result = new List<float>();
            for (int i = 1; i < listValues.Count; i++)
                result.Add(listValues[i - 1] - listValues[i]);
            return result;
        }

        /// <summary>
        /// Tính sự đồng dạng theo Cosine. 
        /// Kết quả [-1,1]
        /// </summary>
        /// <param name="listA">Cùng số lượng với listB</param>
        /// <param name="listB">Cùng số lượng với listA</param>
        /// <returns>Note:-2 listA không bằng listB.</returns>
        public static float MR_TinhCosineSimilar(List<float> listA, List<float> listB)
        {            
            if (listA.Count == listB.Count)
            {
                float result = 0f, temp1 = 0f, temp2 = 0f;
                for (int i = 0; i < listA.Count; i++)
                {
                    temp1 += listA[i] * listA[i];
                    temp2 += listB[i] * listB[i];
                    result += listA[i] * listB[i];
                }

                temp1 = (float)Math.Sqrt(temp1);
                temp2 = (float)Math.Sqrt(temp2);                
                result = (float)Math.Round(result / (temp1 * temp2), 4);
                return result;
            }
            else
                return 0.0f;         
        }

        /// <summary>
        /// Tính độ đồng dạng bằng cách tính độ đồng dạng vector với length là [lengthVector].
        /// Xét trong [maxNumberDay], ngày nào mà ListB có độ đồng dạng lớn nhất với listA thì xét ngày đó là kết quả.
        /// Kết quả xuất ra = 1/[kết quả]. Để đảm bảo kết quả nào nhỏ hơn thì tốt hơn.
        /// </summary>
        /// <param name="listA"></param>
        /// <param name="listB"></param>
        /// <param name="lengthVector">Chiều dài vector trong listA và listB cần tính độ đồng dạng</param>
        /// <param name="maxNumberDay">số ngày trễ tối đa</param>
        /// <returns>0: </returns>
        public static float MR_TinhSimilar_Delay(List<float> listA, List<float> listB,
            int lengthVector, int maxNumberDay,float thresholdSimilar)
        {
            int length = listA.Count;
            if (length > listB.Count) /// lấy chiều dài ngắn nhất trong listA và listB
                length = listB.Count;

            if (length <= lengthVector)
                return 0f;

            List<float> listVectorA = new List<float>();
            List<float> listVectorB = new List<float>();
            int DayMax = -1;
            for (int i = 0; i < lengthVector; i++)
                listVectorA.Add(listA[i]);

            float similar, maxSimilar = -10;

            for (int i = 0; i < maxNumberDay; i++)
            {
                listVectorB = new List<float>();
                for (int j = i; j < length && j < lengthVector + i; j++)
                    listVectorB.Add(listB[j]);

                if (listVectorB.Count == lengthVector)
                {
                    similar = MR_TinhCosineSimilar(listVectorA, listVectorB);
                    if (maxSimilar < similar
                        && similar >= thresholdSimilar)
                    {
                        maxSimilar = similar;
                        DayMax = i;
                    }
                }
            }
            float result;

            //if (maxSimilar > 0)
            //    return maxSimilar;
            //else
            //    return 0f;

            if (DayMax == -1)
                result = 0;
            else
                result = (float)Math.Round((float)1f / (DayMax + 1), 2);
            return result;
        }

        /// <summary>
        /// Tính số lượng các đoạn (theo chu kỳ) giống nhau theo CosineSimilar
        /// </summary>
        /// <param name="listA"></param>
        /// <param name="listB"></param>
        /// <param name="chuky">chu kỳ</param>
        /// <param name="filterCosineSimilar">độ đồng dạng tối thiểu</param>
        /// <returns>số lượng các chu kỳ giống nhau</returns>
        public static int MR_TinhSoLuongCosineSimilar(List<float> listA, List<float> listB, int chuky, float minCosineSimilar)
        {
            if (listA.Count != listB.Count)
                return 0;                                                   /// Không đồng nhất về số lượng thì coi như không đồng dạng

            int count = 0, length;
            float cosineSimilar;
            List<float> list1 = new List<float>();
            List<float> list2 = new List<float>();

            length = listA.Count;

            for (int i = 0; i < length; i = i + chuky)
            {
                list1 = new List<float>();
                list2 = new List<float>();
                for (int j = 0; j < chuky; j++)
                {
                    if (i + j >= length)
                        break;

                    list1.Add(listA[i + j]);
                    list2.Add(listB[i + j]);
                }
                cosineSimilar = MR_TinhCosineSimilar(list1, list2);
                if (cosineSimilar >= minCosineSimilar)
                    count++;
            }

            return count;
        }

        /// <summary>
        /// Tính sự đồng dạng dựa trên Euclid distance. Kết quả từ [0,1]
        /// </summary>
        /// <param name="listA"></param>
        /// <param name="listB"></param>
        /// <returns>Note:-2 listA không bằng listB.</returns>
        public static float MR_TinhEuclidSimilar(List<float> listA, List<float> listB)
        {
            if (listA.Count == listB.Count)
            {
                float temp, result = 0f;
                for (int i = 0; i < listA.Count; i++)
                {
                    temp = listA[i] - listB[i];
                    result += temp * temp;
                }
                result = (float)Math.Sqrt(result);
                result = (float)Math.Round(result, 4);
                return result;
            }
            else
                return -2f;
        }

        public static float MR_TinhPearsonCorrelationCoefficient(List<float> listA, List<float> listB)
        {
            if (listA.Count != listB.Count)
                return -1000;
            float avgA = Tk_GetAverage(listA);
            float avgB = Tk_GetAverage(listB);

            List<float> A_avgA = new List<float>();
            List<float> B_avgB = new List<float>();

            foreach (float val in listA)
                A_avgA.Add(val - avgA);
            foreach (float val in listB)
                B_avgB.Add(val - avgB);

            float tuSo = 0f, mauSo = 0f, t1 = 0f, t2 = 0f;
            for (int i = 0; i < listA.Count; i++)
            {
                tuSo += A_avgA[i] * B_avgB[i];
                t1 += (float)Math.Pow(A_avgA[i], 2);
                t2 += (float)Math.Pow(B_avgB[i], 2);
            }
            mauSo = (float)Math.Sqrt(t1 * t2);

            return (float)Math.Round(tuSo / mauSo, 3);
        }

        /// <summary>
        /// Tính tương đồng giữa 2 list. Nếu A tăng thì B phải tăng.
        /// </summary>
        /// <param name="listA"></param>
        /// <param name="listB"></param>
        /// <returns></returns>
        public static float MR_TinhSimilar_TangGiamCungNhau(List<float> listA, List<float> listB)
        {
            List<bool> listBoolA = new List<bool>();
            List<bool> listBoolB = new List<bool>();
            float result = 0f;
            for (int i = 0; i < listA.Count - 1; i++)
                if (listA[i] >= listA[i + 1])
                    listBoolA.Add(true);
                else
                    listBoolA.Add(false);

            for (int i = 0; i < listB.Count - 1; i++)
                if (listB[i] >= listB[i + 1])
                    listBoolB.Add(true);
                else
                    listBoolB.Add(false);
            int countSame = 0,countMin;
            if (listBoolA.Count > listBoolB.Count)
                countMin = listBoolB.Count;
            else
                countMin = listBoolA.Count;

            for (int i = 0; i < countMin; i++)
                if (listBoolA[i] == listBoolB[i])
                    countSame++;
            result = (float)countSame / countMin;
            result = (float)Math.Round(result, 3);

            return result;
        }

        public static float MR_EuclidDistance_Avg_Std(List<float> listA, List<float> listB)
        {
            float avg_A = Tk_GetAverage(listA);
            float avg_B = Tk_GetAverage(listB);
            float std_A = Tk_PopularStandardDeviation(listA);
            float std_B = Tk_PopularStandardDeviation(listB);
            float temp = (float)(Math.Pow((avg_A * 10000 - avg_B * 10000), 2)
                + Math.Pow((std_A * 10000 - std_B * 10000), 2));
            temp = (float)Math.Sqrt(temp);
            temp = (float)Math.Round(temp, 3);
            return temp;
        }
        /// <summary>
        /// Tính độ bay hơi Volatility của danh sách giá trị
        /// Tham khảo tài liệu: Estimate Stock Volatility
        /// </summary>
        /// <param name="listValue">danh sách giá trị</param>
        /// <param name="dT">quãng thời gian cần để thay đổi. Ví dụ: 1/365</param>
        /// <returns>độ bay hơi</returns>
        public static float MR_TinhVolatility_ContinuousMethod(List<float> listValue, float dT)
        {
            if (listValue.Count == 0)
                return 0f;
            int n = listValue.Count;
            float avgValue = CoreFunctions.Tk_GetAverage(listValue);
            float volatility = 0f;

            foreach (float value in listValue)
                volatility += (float) Math.Pow(value - avgValue, 2);
            volatility = (float) (Math.Sqrt(volatility/(n - 1)) / Math.Sqrt(dT));
            
            return (float)Math.Round(volatility, 3);
        }

        /// <summary>
        /// Tính danh sách độ bay hơi Volatility của danh sách giá trị theo chu kỳ
        /// </summary>
        /// <param name="listValue"></param>
        /// <param name="chuky">chu kỳ</param>
        /// <returns></returns>
        public static List<float> MR_TinhListVolatility(List<float> listValue, int chuky)
        {
            List<float> result = new List<float>();
            List<float> temp = new List<float>();
            for (int i = 0; i < listValue.Count; i++)
            {
                temp = new List<float>();
                for (int j = 0; j < chuky; j++)
                    if (i + j < listValue.Count)
                        temp.Add(listValue[i + j]);
                if (temp.Count == chuky)
                    result.Add(CoreFunctions.MR_TinhVolatility_ContinuousMethod(temp, 1f / chuky));
            }
            return result;
        }

        /// <summary>
        /// Tính toán số Fibonaci thứ n
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        public static ulong MR_Fibonaci(int n)
        {
            if (n == 0) return 0;
            ulong a = 1, b = 2, c;
            for (int i = 3; i <= n; i++)
            {
                c = a + b;
                a = b;
                b = c;
            }
            return a;
        }

        public static List<uint> MR_LietKeFibonaci(int soluong)
        {
            List<uint> result = new List<uint>();
            uint a = 1, b = 2, c, t;
            string str;
            result.Add(1);
            result.Add(1);
            for (int i = 3; i <= soluong; i++)
            {
                c = a + b;
                a = b;
                b = c;

                str = a.ToString();
                if (str.Length > 3)
                    t = uint.Parse(str.Substring(0, 3));
                else
                    t = a;
                if (result.Contains(t) == false)
                    result.Add(t);
            }
            result.Sort();
            foreach (uint so in result)
                Console.Write(so + " ");
            return result;
        }

        /// <summary>
        /// Hàm gộp 2 giá trị liền kề. Nếu 2 giá trị chêch lệch nhỏ hơn percentChechlech
        /// thì gộp lại thành 1 giá trị theo trung bình cộng
        /// Quá trình tính sẽ di chuyển từ cuối về đầu (từ cuối listValue về 0).
        /// </summary>
        /// <param name="listValues"></param>
        /// <param name="percentChechlech">từ 0.0 --> 1.0 </param>
        /// <returns></returns>
        public static List<float> MR_GomGiaTri(List<float> listValues, float percentChechlech)
        {
            List<float> listResult = new List<float>();
            List<float> listTemp = new List<float>(listValues);
            float val = 0f;
            bool flag = false;
            for (int i = listTemp.Count - 1; i > 0; i--)
            {
                if (Math.Abs(Math.Log(listTemp[i] / listTemp[i - 1])) <= percentChechlech)
                {
                    val = (listTemp[i] + listTemp[i - 1]) / 2;
                    listTemp[i - 1] = val;
                    listResult.Insert(0, 0f);
                    //listResult.Insert(0, val);
                    flag = true;
                    i--;
                }
                else
                {
                    if (flag == true)
                    {
                        listResult.Insert(0, val);
                        flag = false;
                    }
                    listResult.Insert(0, listTemp[i]);

                }
            }
            if (flag == true)
            {
                listResult.Insert(0, val);
                flag = false;
            }
            return listResult;
        }

        public static List<float> MR_TinhDaoDongGia(List<float> listVal)
        {           
            List<float> valAddList = new List<float>();
            List<int> listCount = new List<int>();
            
            int count;
            float chechlech;
                      
            listCount = new List<int>();
            valAddList = new List<float>();
            count = 0;

            for (int i = 0; i < 4; i++)
                listCount.Add(0);

            for (int i = 1; i < listVal.Count; i++)
            {
                chechlech = (float)(listVal[i - 1] - listVal[i]) / listVal[i];
                chechlech = (float)Math.Abs(chechlech);
                count++;

                if (chechlech <= 0.01f)
                    listCount[0]++;
                else if (chechlech <= 0.03f)
                    listCount[1]++;
                else if (chechlech <= 0.05f)
                    listCount[2]++;
                else
                    listCount[3]++;
            }

            for (int i = 0; i < listCount.Count; i++)
            {
                chechlech = (float)listCount[i] / count;
                chechlech = (float)Math.Round(chechlech, 2);
                valAddList.Add(chechlech);
            }
           
            return valAddList;
        }

        public static float MR_TinhDaoDongGia(List<float> listValues, float gia, ref string Message)
        {           
            List<float> listDaoDongGia = MR_TinhDaoDongGia(listValues);
            float chechlech = Math.Abs((gia - listValues[0]) / listValues[0]);

            Message = "";
            if (chechlech <= 0.01f)
            {
                Message = "DD Giá <= 1%: " + listDaoDongGia[0] * 100 + "%";
                return listDaoDongGia[0];
            }
            else if (chechlech <= 0.03f)
            {
                Message = "DD Giá <= 3%: " + listDaoDongGia[1] * 100 + "%";
                return listDaoDongGia[1];
            }
            else if (chechlech <= 0.05f)
            {
                Message = "DD Giá <= 5%: " + listDaoDongGia[2] * 100 + "%";
                return listDaoDongGia[2];
            }
            else
            {
                Message = "DD Giá > 5%: " + listDaoDongGia[3] * 100 + "%";
                return listDaoDongGia[3];
            }
        }
        #endregion

        #region ------- Compare
        public static int Compare_ListListString(List<string> listA, List<string> listB)
        {
            if (listA.Count != listB.Count)
                return 0;

            if (listA[0] != listB[0])
                return listA[0].CompareTo(listB[0]);
            else
                return -listA[1].CompareTo(listB[1]);
        }

        public static int Compare_String_THMua(string a, string b)
        {
            string ngaya = a.Split(new string[] { "\t" }, StringSplitOptions.RemoveEmptyEntries)[1];
            string ngayb = b.Split(new string[] { "\t" }, StringSplitOptions.RemoveEmptyEntries)[1];
            return -ngaya.CompareTo(ngayb);
        }

        
        #endregion

        #region ------- Thuộc tính
        public static string HeaderFile
        {
            get
            {
                string text = "Ngay bat dau: " + CoreFunctions.Xuly_ChuyenChuoiDataStock(_ngayBatDau) + " -- Ngay ket thuc: "
                    + CoreFunctions.Xuly_ChuyenChuoiDataStock(_ngayKetThuc) + " -- So ngay giao dich: " + _soNgayGiaoDich.ToString();
                return text;
            }
        }
        #endregion
    }
}
